package com.genius.controller;

import com.genius.annotation.PreFuncAuth;
import com.genius.core.JSONResult;
import com.genius.utils.PageUtils;
import com.genius.workflow.bo.DeleteDefinitionByIdsBO;
import com.genius.workflow.bo.SelectDefinitionByPageBO;
import com.genius.workflow.bo.SelectDefinitionByXmlBO;
import com.genius.workflow.bo.UploadDefinitionBO;
import com.genius.workflow.vo.DeploymentVO;
import com.genius.workflow.vo.ProcessDefinitionVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.FilenameUtils;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

@RestController
@RequestMapping("processDefinition")
@Api(value = "流程定义接口", tags = {"用于流程定义的接口"})
public class DefinitionController {

    @Autowired
    private RepositoryService repositoryService;


    @PostMapping("/selectDefinitionByPage")
    @ApiOperation(value = "流程定义（分页查询）",notes = "查询流程定义分页数据", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:SELECT")
    public JSONResult selectDefinitionByPage(@Valid @RequestBody SelectDefinitionByPageBO selectDefinitionByPageBO){
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        List<ProcessDefinitionVO> processDefinitionVOList = new ArrayList<>();
        for(ProcessDefinition processDefinition : list){
            ProcessDefinitionVO processDefinitionVO = new ProcessDefinitionVO();
            processDefinitionVO.setDefinitionId(processDefinition.getId());
            processDefinitionVO.setName(processDefinition.getName());
            processDefinitionVO.setDefinitionKey(processDefinition.getKey());
            processDefinitionVO.setResourceName(processDefinition.getResourceName());
            processDefinitionVO.setDeploymentId(processDefinition.getDeploymentId());
            processDefinitionVO.setVersion(processDefinition.getVersion());
            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();
            processDefinitionVO.setDeploymentName(deployment.getName());
            processDefinitionVO.setDeploymentTime(deployment.getDeploymentTime());
            processDefinitionVOList.add(processDefinitionVO);
        }
        Integer pageNum = selectDefinitionByPageBO.getPageNum();
        Integer pageSize = selectDefinitionByPageBO.getPageSize();
        Map<String,Object> result = PageUtils.getResultTableData(processDefinitionVOList,pageNum,pageSize);
        return JSONResult.ok(result);
    }

    @PostMapping("/uploadDefinitionByFile")
    @ApiOperation(value = "上传流程定义文件",notes = "上传流程定义文件", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:UPLOAD")
    public JSONResult uploadDefinitionByFile(@RequestParam("processFile")MultipartFile multipartFile){
        //获取上传文件名
        String fileName = multipartFile.getOriginalFilename();
        //获取文件扩展名
        String extension = FilenameUtils.getExtension(fileName);

        String name = FilenameUtils.getName(fileName);
        //获取文件字节流对象
        Deployment deployment;
        try {
            InputStream fileInputStream = multipartFile.getInputStream();
            assert extension != null;
            if(extension.equals("zip")){
                ZipInputStream zipInputStream = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment()
                        .addZipInputStream(zipInputStream)
                        .name(name)
                        .deploy();
            }else{
                deployment = repositoryService.createDeployment()
                        .addInputStream(fileName, fileInputStream)
                        .name(name)
                        .deploy();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Map<String,Object> result = new HashMap<>();
        result.put("deployment",deployment);
        return JSONResult.ok(result);
    }

    @PostMapping("/uploadDefinitionByCode")
    @ApiOperation(value = "上传流程定义编码",notes = "上传流程定义编码", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:UPLOAD")
    public JSONResult uploadDefinitionByCode(@Valid @RequestBody UploadDefinitionBO uploadDefinitionBO){
        Deployment deployment = repositoryService.createDeployment()
                .addString("createWithBPMNJS.bpmn",uploadDefinitionBO.getBpmnTemplate())
                .name(uploadDefinitionBO.getDeploymentName())
                .deploy();

        Map<String,Object> result = new HashMap<>();
        result.put("deployment",deployment);
        return JSONResult.ok(result);
    }

    @PostMapping("/selectDefinitionXmlById")
    @ApiOperation(value = "获取流程定义XML",notes = "获取流程定义XML", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:SELECT")
    public JSONResult selectDefinitionXmlById(@Valid @RequestBody SelectDefinitionByXmlBO selectDefinitionByXmlBO){

        BpmnModel bpmnModel = repositoryService.getBpmnModel(selectDefinitionByXmlBO.getDefinitionId());
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        //把bpmnModel对象转换成字符
        byte[] bytes = converter.convertToXML(bpmnModel);
        String bpmnTemplate = new String(bytes);
        Map<String,Object> result = new HashMap<>();
        result.put("bpmnTemplate",bpmnTemplate);
        return JSONResult.ok(result);
    }

    @PostMapping("/selectDeploymentByPage")
    @ApiOperation(value = "流程部署（分页查询）",notes = "查询流程部署分页数据", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:SELECT")
    public JSONResult selectDeploymentByPage(@Valid @RequestBody SelectDefinitionByPageBO selectDefinitionByPageBO){
        List<Deployment> deploymentList = repositoryService.createDeploymentQuery().list();
        List<DeploymentVO> deploymentVOList = new ArrayList<>();
        for(Deployment deployment : deploymentList){
            DeploymentVO deploymentVO = new DeploymentVO();
            deploymentVO.setId(deployment.getId());
            deploymentVO.setName(deployment.getName());
            deploymentVO.setDeploymentTime(deployment.getDeploymentTime());
            deploymentVOList.add(deploymentVO);
        }
        Integer pageNum = selectDefinitionByPageBO.getPageNum();
        Integer pageSize = selectDefinitionByPageBO.getPageSize();
        Map<String,Object> result = PageUtils.getResultTableData(deploymentVOList,pageNum,pageSize);
        return JSONResult.ok(result);
    }

    @PostMapping("/deleteDefinitionById")
    @ApiOperation(value = "删除流程定义",notes = "删除流程定义", httpMethod = "POST")
    @PreFuncAuth("PROCESS:DEFINITION:DELETE")
    public JSONResult deleteDefinitionById(@Valid @RequestBody DeleteDefinitionByIdsBO deleteDefinitionByIdsBO){
        for(String definitionId:deleteDefinitionByIdsBO.getDefinitionIds()){
            try {
                repositoryService.deleteDeployment(definitionId,true);
            }catch (Exception e){
                return JSONResult.errorMsg("删除失败，ID: "+definitionId+" 不存在");
            }
        }
        return JSONResult.ok("删除成功");
    }
}
